#include "Ast.h"
#include "SymbolTable.h"
#include "Unit.h"
#include "Instruction.h"
#include "IRBuilder.h"
#include <string>
#include <stdbool.h>
#include "Type.h"
extern Unit unit;
extern FILE *yyout;
int Node::counter = 0;
IRBuilder* Node::builder = nullptr;
Type *retType;
bool retStmt=false;
bool isCond=false;

Node::Node()
{
    seq = counter++;
}

void Node::setNext(Node* node) {
    Node* n = this;
    while (n->getNext()) {
        n = n->getNext();
    }
    if (n == this) {
        this->next = node;
    } else {
        n->setNext(node);
    }
}

void Node::backPatch(std::vector<Instruction*> &list, BasicBlock*bb)
{
    for(auto &inst:list)
    {
        if(inst->isCond())
            dynamic_cast<CondBrInstruction*>(inst)->setTrueBranch(bb);
        else if(inst->isUncond())
            dynamic_cast<UncondBrInstruction*>(inst)->setBranch(bb);
    }
}

std::vector<Instruction*> Node::merge(std::vector<Instruction*> &list1, std::vector<Instruction*> &list2)
{
    std::vector<Instruction*> res(list1);
    res.insert(res.end(), list2.begin(), list2.end());
    return res;
}

void Ast::genCode(Unit *unit)
{
    IRBuilder *builder = new IRBuilder(unit);
    Node::setIRBuilder(builder);
    root->genCode();
}

void FunctionDef::genCode()
{
    Unit *unit = builder->getUnit();
    Function *func = new Function(unit, se);
    BasicBlock *entry = func->getEntry();
    // set the insert point to the entry basicblock of this function.
    builder->setInsertBB(entry);
    if (decl)
        decl->genCode();
    if (stmt)
        stmt->genCode();
    for (auto block = func->begin(); block != func->end(); block++) {
        //获取该块的最后一条指令
        Instruction *first = (*block)->begin();
        Instruction *last = (*block)->rbegin();
        //从块中删除条件型语句
        while (first != last) {
            if (first->isCond() || first->isUncond()) {
                (*block)->remove(first);
            }
            first = first->getNext();
        }
        // 有条件跳转指令：加上前序和后继
        if (last->isCond()) {
            BasicBlock *truebranch, *falsebranch;
            truebranch = dynamic_cast<CondBrInstruction*>(last)->getTrueBranch();
            falsebranch = dynamic_cast<CondBrInstruction*>(last)->getFalseBranch();
            if(truebranch) {
                (*block)->addSucc(truebranch);
                truebranch->addPred(*block);
            }
            if(falsebranch) {
                (*block)->addSucc(falsebranch);
                falsebranch->addPred(*block);
            } 
        } 
        // 无条件跳转指令：获取跳转的目标块
        else if (last->isUncond()) {
            BasicBlock* dst = dynamic_cast<UncondBrInstruction*>(last)->getBranch();
            (*block)->addSucc(dst);
            // 如果无条件跳转的目标块为空，插入return
            dst->addPred(*block);
            if (dst->empty()) {
                if (((FunctionType*)(se->getType()))->getRetType() == TypeSystem::intType)
                    new RetInstruction(new Operand(new ConstantSymbolEntry(TypeSystem::intType, 0)), dst);
                else if (((FunctionType*)(se->getType()))->getRetType() == TypeSystem::voidType)
                    new RetInstruction(nullptr, dst);
            }
            
        }
        // 没有显示返回或者跳转的语句，插入空return
        else if ((!last->isRet())&&((FunctionType*)(se->getType()))->getRetType()==TypeSystem::voidType) {
            new RetInstruction(nullptr, *block);
        }
    }
}

void BinaryExpr::genCode()
{
    BasicBlock *bb = builder->getInsertBB();
    Function *func = bb->getParent();
    if (op == AND)
    {
        BasicBlock *trueBB = new BasicBlock(func);  // if the result of lhs is true, jump to the trueBB.
        expr1->genCode();
        if(isCond && (expr1->getType()!=TypeSystem::boolType))
            expr1->intToBool();
        backPatch(expr1->trueList(), trueBB);
        builder->setInsertBB(trueBB);               // set the insert point to the trueBB so that intructions generated by expr2 will be inserted into it.
        expr2->genCode();
        if(isCond && (expr2->getType()!=TypeSystem::boolType))
            expr2->intToBool();
        true_list = expr2->trueList();
        false_list = merge(expr1->falseList(), expr2->falseList());
    }
    else if(op == OR)
    {
        BasicBlock* trueBB = new BasicBlock(func);  // 如果表达式结果为真，跳转到trueBB
        expr1->genCode();
        if(isCond && (expr1->getType()!=TypeSystem::boolType))
            expr1->intToBool();
        backPatch(expr1->falseList(), trueBB);      // expr1的falseList跳转到trueBB，也就是如果expr1为假，才继续判断expr2
        builder->setInsertBB(trueBB);               // expr2的插入点为trueBB
        expr2->genCode();
        if(isCond && (expr2->getType()!=TypeSystem::boolType))
            expr2->intToBool();
        true_list = merge(expr1->trueList(), expr2->trueList());
        false_list = expr2->falseList();
    }
    else if(op >= EQ && op <= LES)
    {
        expr1->genCode();
        expr2->genCode();
        Operand *src1 = expr1->getOperand();
        Operand *src2 = expr2->getOperand();
        // 需要将i1零扩展为i32
        if (src1->getType()->getSize() == 1) {
            Operand* dst = new Operand(new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel()));
            new ZextInstruction(dst, src1, bb);
            src1 = dst;
        }
        if (src2->getType()->getSize() == 1) {
            Operand* dst = new Operand(new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel()));
            new ZextInstruction(dst, src2, bb);
            src2 = dst;
        }
        int opcode;
        switch (op) {
        case EQ:
            opcode = CmpInstruction::EQ;
            break;
        case GEQ:
            opcode = CmpInstruction::GEQ;
            break;
        case LEQ:
            opcode = CmpInstruction::LEQ;
            break;
        case NEQ:
            opcode = CmpInstruction::NEQ;
            break;
        case GRA:
            opcode = CmpInstruction::GRA;
            break;
        case LES:
            opcode = CmpInstruction::LES;
            break;
        default:
            break;
        }
        new CmpInstruction(opcode, dst, src1, src2, bb);
        dst->getSymPtr()->setType(TypeSystem::boolType);
        BasicBlock *truebb, *falsebb, *tempbb;
        truebb = new BasicBlock(func);
        falsebb = new BasicBlock(func);
        tempbb = new BasicBlock(func);
        true_list.push_back(new CondBrInstruction(truebb, tempbb, dst, bb));
        false_list.push_back(new UncondBrInstruction(falsebb, tempbb));
    }
    else if(op >= ADD && op <= MOD)
    {
        expr1->genCode();
        expr2->genCode();
        Operand *src1 = expr1->getOperand();
        Operand *src2 = expr2->getOperand();
        int opcode;
        switch (op)
        {
        case ADD:
            opcode = BinaryInstruction::ADD;
            break;
        case SUB:
            opcode = BinaryInstruction::SUB;
            break;
        case MUL:
            opcode = BinaryInstruction::MUL;
            break;
        case DIV:
            opcode = BinaryInstruction::DIV;
            break;
        case MOD:
            opcode = BinaryInstruction::MOD;
            break;
        }
        new BinaryInstruction(opcode, dst, src1, src2, bb);
    }
}

void Constant::genCode()
{
    // we don't need to generate code.
}

void Id::genCode()
{
    BasicBlock *bb = builder->getInsertBB();
    Operand *addr = dynamic_cast<IdentifierSymbolEntry*>(symbolEntry)->getAddr();
    new LoadInstruction(dst, addr, bb);
}

void IfStmt::genCode()
{
    Function *func;
    BasicBlock *then_bb, *end_bb;

    func = builder->getInsertBB()->getParent();
    then_bb = new BasicBlock(func);
    end_bb = new BasicBlock(func);
    isCond = true;
    cond->genCode();
    isCond = false;
    backPatch(cond->trueList(), then_bb);
    backPatch(cond->falseList(), end_bb);

    builder->setInsertBB(then_bb);
    thenStmt->genCode();
    then_bb = builder->getInsertBB();
    new UncondBrInstruction(end_bb, then_bb);

    builder->setInsertBB(end_bb);
}

void IfElseStmt::genCode()
{
    Function *func;
    BasicBlock *then_bb, *else_bb, *end_bb;

    func = builder->getInsertBB()->getParent();
    then_bb = new BasicBlock(func);
    end_bb = new BasicBlock(func);
    else_bb = new BasicBlock(func);
    isCond = true;
    cond->genCode();
    isCond = false;
    backPatch(cond->trueList(), then_bb);
    backPatch(cond->falseList(), else_bb);

    builder->setInsertBB(then_bb);
    thenStmt->genCode();
    then_bb = builder->getInsertBB();
    new UncondBrInstruction(end_bb, then_bb);

    builder->setInsertBB(else_bb);
    elseStmt->genCode();
    else_bb = builder->getInsertBB();
    new UncondBrInstruction(end_bb, else_bb);

    builder->setInsertBB(end_bb);
}

void CompoundStmt::genCode()
{
    stmt->genCode();
}

void SeqNode::genCode()
{
    stmt1->genCode();
    stmt2->genCode();
}

void DeclStmt::genCode()
{
    IdentifierSymbolEntry *se = dynamic_cast<IdentifierSymbolEntry *>(id->getSymPtr());
    if(se->isGlobal())
    {
        Operand *addr;
        SymbolEntry *addr_se;
        addr_se = new IdentifierSymbolEntry(*se);
        addr_se->setType(new PointerType(se->getType()));
        addr = new Operand(addr_se);
        se->setAddr(addr);
        unit.insertGlobal(se);
    }
    else if(se->isLocal())
    {
        Function *func = builder->getInsertBB()->getParent();
        BasicBlock *entry = func->getEntry();
        Instruction *alloca;
        Operand *addr;
        SymbolEntry *addr_se;
        Type *type;
        type = new PointerType(se->getType());
        addr_se = new TemporarySymbolEntry(type, SymbolTable::getLabel());
        addr = new Operand(addr_se);
        alloca = new AllocaInstruction(addr, se);                   // allocate space for local id in function stack.
        entry->insertFront(alloca);                                 // allocate instructions should be inserted into the begin of the entry block.
        se->setAddr(addr);                                          // set the addr operand in symbol entry so that we can use it in subsequent code generation.
    }
    else if(se->isParam()) {
        Function* func = builder->getInsertBB()->getParent();
        BasicBlock* entry = func->getEntry();
        Instruction* alloca;
        Operand* addr;
        SymbolEntry* addr_se;
        Type* type;
        type = new PointerType(se->getType());
        addr_se = new TemporarySymbolEntry(type, SymbolTable::getLabel());
        addr = new Operand(addr_se);
        alloca = new AllocaInstruction(addr, se);
        entry->insertFront(alloca); 
        // 如果是参数，需要store
        Operand *src = se->getAddr();
        BasicBlock* bb = builder->getInsertBB();
        new StoreInstruction(addr, src, bb);
        se->setAddr(addr);  
    }
    // 定义时还声明了初始值，需要store
    if(expr) {
        BasicBlock *bb = builder->getInsertBB();
        expr->genCode();
        Operand *addr = dynamic_cast<IdentifierSymbolEntry*>(id->getSymPtr())->getAddr();
        Operand *src = expr->getOperand();
        new StoreInstruction(addr, src, bb);
    }
    if (this->getNext()) {
        this->getNext()->genCode();
    }
}

void ReturnStmt::genCode()
{
    BasicBlock *bb=builder->getInsertBB();
    retValue->genCode();
    Operand *src=retValue->getOperand();
    new RetInstruction(src, bb);
}

void AssignStmt::genCode()
{
    BasicBlock *bb = builder->getInsertBB();
    expr->genCode();
    Operand *addr = dynamic_cast<IdentifierSymbolEntry*>(lval->getSymPtr())->getAddr();
    Operand *src = expr->getOperand();
    /***
     * We haven't implemented array yet, the lval can only be ID. So we just store the result of the `expr` to the addr of the id.
     * If you want to implement array, you have to caculate the address first and then store the result into it.
     */
    new StoreInstruction(addr, src, bb);
}

void BlankStmt::genCode() {

}

void ExprStmt::genCode() {
    expr->genCode();
}

void CallFunc::genCode() {
    if (((IdentifierSymbolEntry*)symbolEntry)->isSysy())
        unit.insertLibfunc(symbolEntry);
    std::vector<Operand*> operands;
    ExprNode* temp = param;
    while (temp) {
        temp->genCode();
        operands.push_back(temp->getOperand());
        temp = ((ExprNode*)temp->getNext());
    }
    BasicBlock* bb = builder->getInsertBB();
    new CallInstruction(dst, symbolEntry, operands, bb);
}

void ContinueStmt::genCode() {
    Function* func = builder->getInsertBB()->getParent();
    BasicBlock* bb = builder->getInsertBB();
    new UncondBrInstruction(((WhileStmt*)whileStmt)->get_cond_bb(), bb);
    BasicBlock* continue_next_bb = new BasicBlock(func);
    builder->setInsertBB(continue_next_bb);
}

void BreakStmt::genCode() {
    Function* func = builder->getInsertBB()->getParent();
    BasicBlock* bb = builder->getInsertBB();
    new UncondBrInstruction(((WhileStmt*)whileStmt)->get_end_bb(), bb);
    BasicBlock* break_next_bb = new BasicBlock(func);
    builder->setInsertBB(break_next_bb);
}

void WhileStmt::genCode() {
    Function* func;
    BasicBlock *cond_bb, *while_bb, *end_bb, *bb;
    bb = builder->getInsertBB();
    func = builder->getInsertBB()->getParent();
    cond_bb = new BasicBlock(func);
    while_bb = new BasicBlock(func);
    end_bb = new BasicBlock(func);

    this->cond_bb = cond_bb;
    this->end_bb = end_bb;

    new UncondBrInstruction(cond_bb, bb);

    builder->setInsertBB(cond_bb);
    isCond = true;
    cond->genCode();
    isCond = false;
    backPatch(cond->trueList(), while_bb);
    backPatch(cond->falseList(), end_bb);
    
    builder->setInsertBB(while_bb);
    stmt->genCode();

    while_bb = builder->getInsertBB();
    new UncondBrInstruction(cond_bb, while_bb);

    builder->setInsertBB(end_bb);
}

void FuncParam::genCode() {

}

void ConstId::genCode() {

}

void ExprNode::genCode() {
    
}

void UnaryExpr::genCode() {
    expr->genCode();
    BasicBlock* bb = builder->getInsertBB();
    if (op == NOT) {
        Operand* src = expr->getOperand();
        // 先和0比较大小 然后对于结果进行取反
        Operand* temp = new Operand(new TemporarySymbolEntry(TypeSystem::boolType, SymbolTable::getLabel()));
        new CmpInstruction(CmpInstruction::NEQ, temp, src, new Operand(new ConstantSymbolEntry(TypeSystem::intType, 0)), bb);
        src = temp;
        new XorInstruction(dst, src, bb);
        type = src->getType();
    } 
    // -x的情况下，用0-x 
    else if (op == SUB) {
        Operand* src1 = new Operand(new ConstantSymbolEntry(TypeSystem::intType, 0));
        Operand* src2;
        // 将i1零扩展为i32
        if (expr->getType()->getSize() == 1) {
            src2 = new Operand(new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel()));
            new ZextInstruction(src2, expr->getOperand(), bb);
        } 
        else
            src2 = expr->getOperand();
        new BinaryInstruction(BinaryInstruction::SUB, dst, src1, src2, bb);
    }
    if(isCond) 
        intToBool();
}

void Ast::typeCheck()
{
    if(root != nullptr)
        root->typeCheck();
}

void FunctionDef::typeCheck()
{
    retType=((FunctionType*)(se->getType()))->getRetType(); // 正确的返回值类型，returnStmt的类型检查中使用
    retStmt=false;  // 记录是否有return语句
    if(stmt) {
        stmt->typeCheck();
        if(!retStmt&&retType!=TypeSystem::voidType) {
            fprintf(stderr, "Non-void function has no return!\n");
            exit(EXIT_FAILURE);
        }
    }
    // 如果函数定义中为空，检查是否为void函数
    else {
        if(retType!=TypeSystem::voidType) {
            fprintf(stderr, "Non-void function has no return!\n");
            exit(EXIT_FAILURE);
        }
    }
    
}

void BinaryExpr::typeCheck()
{
    expr1 -> typeCheck();
    expr2 -> typeCheck();
    Type *type1 = expr1 -> getSymPtr() -> getType();
    Type *type2 = expr2 -> getSymPtr() -> getType();
    if(type1 -> isFunc()) {
        type1 = ((FunctionType*)type1)->getRetType();
        if(type1 -> isVoid()) {
            fprintf(stderr, "The operand's type cannnt be void\n");
            exit(EXIT_FAILURE);
        }
    }
    if(type2 -> isFunc()) {
        type2 = ((FunctionType*)type2)->getRetType();
        if(type2 -> isVoid()) {
            fprintf(stderr, "The operand's type cannnt be void\n");
            exit(EXIT_FAILURE);
        }
    }
    if((type1->isArray()|type1->isInt())&&(type2->isArray()|type2->isInt()));
    else if(type1->getKind() != type2->getKind()){
        fprintf(stderr, "type %s and %s do not match\n", type1 -> toStr().c_str(), type2 -> toStr().c_str());
        exit(EXIT_FAILURE);
    }
    symbolEntry -> setType(type1);
    // 隐式转换
    if (op >= BinaryExpr::AND && op <= BinaryExpr::LES) {
        fprintf(stderr, "Implicit conversion from int to bool\n");
        type = TypeSystem::boolType;
    }
    else
        type = TypeSystem::intType;
}

void Constant::typeCheck()
{
    // Todo
}

void Id::typeCheck()
{
    // Todo
}

void IfStmt::typeCheck()
{
    cond -> typeCheck();
    if(thenStmt){
        thenStmt -> typeCheck();
    }
}

void IfElseStmt::typeCheck()
{
    cond -> typeCheck();
    if(thenStmt){
        thenStmt -> typeCheck();
    }
    elseStmt -> typeCheck();
}

void CompoundStmt::typeCheck()
{
    // Todo
    if(stmt) {
        stmt->typeCheck();
    }
}

void SeqNode::typeCheck()
{
    // Todo
    if(stmt1) {
        stmt1->typeCheck();
    }
    if(stmt2) {
        stmt2->typeCheck();
    }
}

void DeclStmt::typeCheck()
{
    // Todo
    id->typeCheck();
    if(expr) {
        expr->typeCheck();
    }
}

void WhileStmt::typeCheck() {
    if(cond)
        cond->typeCheck();
    if(stmt)
        stmt->typeCheck();
}

void BreakStmt::typeCheck() {

}

void ContinueStmt::typeCheck() {

}

void BlankStmt::typeCheck() {

}

void ExprStmt::typeCheck() {

}

void ReturnStmt::typeCheck()
{
    retStmt=true;
    if(retValue) {
        retValue->typeCheck();
        if(retValue->getType()->getKind()!=retType->getKind()) {
            fprintf(stderr, "The return value's type \'%s\' and the function's type \'%s\' do not match\n",
                retValue->getType()->toStr().c_str(), retType->toStr().c_str());
            exit(EXIT_FAILURE);
        }
    }
}

void AssignStmt::typeCheck()
{
    lval->typeCheck();
    expr->typeCheck();
    // 检查赋值之前是否先定义了的代码写在parsey.y的LVal处
    SymbolEntry* se = lval->getSymPtr();
    // 赋值语句检查左值是否可以被赋值，右值是否为整型（后续要加上浮点数的判断！）
    Type* type = ((Id*)lval)->getType();
    if (type->isInt()) {
        if (((IntType*)type)->isConst()) {
            fprintf(stderr, "Cannot assign constant type with \'%s\' type \'%s\'\n", ((IdentifierSymbolEntry*)se)->toStr().c_str(), type->toStr().c_str());
            exit(EXIT_FAILURE);
        }
    } 
    if (!expr->getType()->isInt()) {
        fprintf(stderr, "Cannot assign int variable with type \'%s\'\n", expr->getType()->toStr().c_str());
        exit(EXIT_FAILURE);
    }
}

void CallFunc::typeCheck() {
    // 检查参数类型、数量是否正确
    if (symbolEntry) {
        std::vector<Type*> params = ((FunctionType*)(symbolEntry->getType()))->getParamsType();
        ExprNode* temp = param;
        for (auto it = params.begin(); it != params.end(); it++) {
            if (temp == nullptr) {
                fprintf(stderr, "Not enough arguments for function %s %s\n", symbolEntry->toStr().c_str(), type->toStr().c_str());
                exit(EXIT_FAILURE);
            } 
            temp->typeCheck();
            if ((*it)->getKind() != temp->getType()->getKind()) {
                fprintf(stderr, "Argument's type %s doesn't match with %s\n", temp->getType()->toStr().c_str(), (*it)->toStr().c_str());
                exit(EXIT_FAILURE);
            }
            temp = (ExprNode*)(temp->getNext());
        }
        if (temp != nullptr) {
            fprintf(stderr, "Too many arguments for function %s %s\n", symbolEntry->toStr().c_str(), type->toStr().c_str());
            exit(EXIT_FAILURE);
        }
    }
}

void FuncParam::typeCheck() {

}

void ConstId::typeCheck() {

}

void ExprNode::typeCheck() {

}

void UnaryExpr::typeCheck() {
    expr->typeCheck();
    if (expr->getType()->isVoid()) {
        std::string op_str;
        if (op == UnaryExpr::NOT)
            op_str = "!";
        else
            op_str = "-";
        fprintf(stderr, "Invalid operand of type \'void\' to unary \'opeartor%s\'\n", op_str.c_str());
        exit(EXIT_FAILURE);
    }
}

void BinaryExpr::output(int level)
{
    std::string op_str;
    switch(op)
    {
        case ADD:
            op_str = "+";
            break;
        case SUB:
            op_str = "-";
            break;
        case MUL:
            op_str = "*";
            break;
        case DIV:
            op_str = "/";
            break;
        case MOD:
            op_str = "%";
            break;
        case AND:
            op_str = "&&";
            break;
        case OR:
            op_str = "||";
            break;
        case EQ:
            op_str = "==";
            break;
        case GEQ:
            op_str = ">=";
            break;
        case LEQ:
            op_str = "<=";
            break;
        case NEQ:
            op_str = "!=";
            break;
        case GRA:
            op_str = ">";
            break;
        case LES:
            op_str = "<";
            break;
    }
    fprintf(yyout, "%*cBinaryExpr\top: %s\n", level, ' ', op_str.c_str());
    expr1->output(level + 4);
    expr2->output(level + 4);
}

void UnaryExpr::output(int level)
{
    std::string op_str;
    switch (op) {
        case NOT:
            op_str = "not";
            break;
        case SUB:
            op_str = "minus";
            break;
    }
    fprintf(yyout, "%*cUnaryExpr\top: %s\n", level, ' ', op_str.c_str());
    expr->output(level + 4);
}

void Ast::output()
{
    fprintf(yyout, "program\n");
    if(root != nullptr)
        root->output(4);
}

void ExprNode::output(int level) {
    std::string name, type;
    name = symbolEntry->toStr();
    type = symbolEntry->getType()->toStr();
    fprintf(yyout, "%*cconst string\ttype:%s\t%s\n", level, ' ', type.c_str(),
            name.c_str());
}

void Constant::output(int level)
{
    std::string type, value;
    type = symbolEntry->getType()->toStr();
    value = symbolEntry->toStr();
    _Bool isFloat = false;
    for(long unsigned int i = 0; i < value.length(); i++) {
        if(value[i] == '.') {
            isFloat = true;
            break;
        }
    }
    if(isFloat) {
        fprintf(yyout, "%*cFloatLiteral\tvalue: %s\ttype: %s\n", level, ' ',
            value.c_str(), type.c_str());
    }
    else {
        fprintf(yyout, "%*cIntegerLiteral\tvalue: %s\ttype: %s\n", level, ' ',
            value.c_str(), type.c_str());
    }
}

void Id::output(int level)
{
    std::string name, type;
    int scope;
    name = symbolEntry->toStr();
    type = symbolEntry->getType()->toStr();
    scope = dynamic_cast<IdentifierSymbolEntry*>(symbolEntry)->getScope();
    fprintf(yyout, "%*cId\tname: %s\tscope: %d\ttype: %s\n", level, ' ',
            name.c_str(), scope, type.c_str());
}

void ConstId::output(int level)
{
    std::string name, type;
    int scope;
    name = symbolEntry->toStr();
    type = symbolEntry->getType()->toStr();
    scope = dynamic_cast<IdentifierSymbolEntry*>(symbolEntry)->getScope();
    fprintf(yyout, "%*cConstId\tname: %s\tscope: %d\ttype: %s\n", level, ' ',
            name.c_str(), scope, type.c_str());
}

void FuncParam::output(int level)
{
    std::string name, type;
    int scope;
    name = symbolEntry -> toStr();
    type = symbolEntry -> getType() -> toStr();
    scope = dynamic_cast<IdentifierSymbolEntry*>(symbolEntry) -> getScope();
    fprintf(yyout, "%*cFuncFParam\tname:%s\tscope:%d\ttype:%s\n", level, ' ',
            name.c_str(), scope, type.c_str());
}

void CompoundStmt::output(int level)
{
    fprintf(yyout, "%*cCompoundStmt\n", level, ' ');
    stmt->output(level + 4);
}

void SeqNode::output(int level)
{
    stmt1->output(level);
    stmt2->output(level);
}

void DeclStmt::output(int level)
{
    fprintf(yyout, "%*cDeclStmt\n", level, ' ');
    id->output(level + 4);
    if (expr)
        expr->output(level + 4);
    if (this->getNext()) {
        this->getNext()->output(level);
    }
}

void IfStmt::output(int level)
{
    fprintf(yyout, "%*cIfStmt\n", level, ' ');
    cond->output(level + 4);
    thenStmt->output(level + 4);
}

void IfElseStmt::output(int level)
{
    fprintf(yyout, "%*cIfElseStmt\n", level, ' ');
    cond->output(level + 4);
    thenStmt->output(level + 4);
    elseStmt->output(level + 4);
}

void WhileStmt::output(int level) {
    fprintf(yyout, "%*cWhileStmt\n", level, ' ');
    cond->output(level + 4);
    stmt->output(level + 4);
}

void BreakStmt::output(int level) {
    fprintf(yyout, "%*cBreakStmt\n", level, ' ');
}

void ContinueStmt::output(int level) {
    fprintf(yyout, "%*cContinueStmt\n", level, ' ');
}

void ReturnStmt::output(int level)
{
    fprintf(yyout, "%*cReturnStmt\n", level, ' ');
    retValue->output(level + 4);
}

void AssignStmt::output(int level)
{
    fprintf(yyout, "%*cAssignStmt\n", level, ' ');
    lval->output(level + 4);
    expr->output(level + 4);
}

void FunctionDef::output(int level)
{
    std::string name, type;
    name = se->toStr();
    type = se->getType()->toStr();
    fprintf(yyout, "%*cFunctionDefine function name: %s, type: %s\n", level, ' ', 
            name.c_str(), type.c_str());
    if (decl) {
        decl->output(level + 4);
    }
    stmt->output(level + 4);
}

void CallFunc::output(int level) {
    std::string name, type;
    int scope;
    if (symbolEntry) {
        name = symbolEntry->toStr();
        type = symbolEntry->getType()->toStr();
        scope = dynamic_cast<IdentifierSymbolEntry*>(symbolEntry)->getScope();
        fprintf(yyout, "%*cCallFunc\tfunction name: %s\tscope: %d\ttype: %s\n", level, ' ', name.c_str(), scope, type.c_str());
        Node* temp = param;
        while (temp) {
            temp->output(level + 4);
            temp = temp->getNext();
        }
    }
}

void ExprStmt::output(int level) {
    fprintf(yyout, "%*cExprStmt\n", level, ' ');
    expr->output(level + 4);
}

void BlankStmt::output(int level) {
    fprintf(yyout, "%*cBlankStmt\n", level, ' ');
}

CallFunc::CallFunc(SymbolEntry* se, ExprNode* param) : ExprNode(se), param(param) {
    dst = nullptr;
    SymbolEntry* s = se;
    int paramNo = 0;
    ExprNode* temp = param;
    while (temp) {
        paramNo++;
        temp = (ExprNode*)(temp->getNext());
    }
    while (s) {
        Type* type = s->getType();
        std::vector<Type*> params = ((FunctionType*)type)->getParamsType();
        if ((long unsigned int)paramNo == params.size()) {
            this->symbolEntry = s;
            break;
        }
        s = s->getNext();
    }
    if (symbolEntry) {
        this->type = ((FunctionType*)symbolEntry->getType())->getRetType();
        if (this->type != TypeSystem::voidType) {
            SymbolEntry* se = new TemporarySymbolEntry(this->type, SymbolTable::getLabel());
            dst = new Operand(se);
        }
    }
}

UnaryExpr::UnaryExpr(SymbolEntry* se, int op, ExprNode* expr): ExprNode(se), op(op), expr(expr) {
    type = TypeSystem::intType;
    dst = new Operand(se);
};

BinaryExpr::BinaryExpr(SymbolEntry *se, int op, ExprNode*expr1, ExprNode*expr2) 
    : ExprNode(se), op(op), expr1(expr1), expr2(expr2) {
    dst = new Operand(se);
    if (op >= BinaryExpr::AND && op <= BinaryExpr::LES) {
        this->symbolEntry->setType(TypeSystem::boolType);
    }
};

int BinaryExpr::getValue() {
    int value = 0;
    switch (op) {
        case ADD:
            value = expr1->getValue() + expr2->getValue();
            break;
        case SUB:
            value = expr1->getValue() - expr2->getValue();
            break;
        case MUL:
            value = expr1->getValue() * expr2->getValue();
            break;
        case DIV:
            if(expr2->getValue())
                value = expr1->getValue() / expr2->getValue();
            break;
        case MOD:
            value = expr1->getValue() % expr2->getValue();
            break;
        case AND:
            value = expr1->getValue() && expr2->getValue();
            break;
        case OR:
            value = expr1->getValue() || expr2->getValue();
            break;
        case LES:
            value = expr1->getValue() < expr2->getValue();
            break;
        case LEQ:
            value = expr1->getValue() <= expr2->getValue();
            break;
        case GRA:
            value = expr1->getValue() > expr2->getValue();
            break;
        case GEQ:
            value = expr1->getValue() >= expr2->getValue();
            break;
        case EQ:
            value = expr1->getValue() == expr2->getValue();
            break;
        case NEQ:
            value = expr1->getValue() != expr2->getValue();
            break;
    }
    return value;
}

int UnaryExpr::getValue() {
    int value = 0;
    switch (op) {
        case NOT:
            value = !(expr->getValue());
            break;
        case SUB:
            value = -(expr->getValue());
            break;
    }
    return value;
}

int Constant::getValue() {
    return ((ConstantSymbolEntry*)symbolEntry)->getValue();
}

int Id::getValue() {
    return ((IdentifierSymbolEntry*)symbolEntry)->getValue();
}

Constant::Constant(SymbolEntry *se) : ExprNode(se){
    dst = new Operand(se);
    type = TypeSystem::intType;
};

void ExprNode::intToBool() {
    BasicBlock* bb = builder->getInsertBB();
    Function* func = bb->getParent();
    BasicBlock *truebb, *falsebb, *tempbb;
    truebb = new BasicBlock(func);
    falsebb = new BasicBlock(func);
    tempbb = new BasicBlock(func);
    Operand* temp = new Operand(new TemporarySymbolEntry(TypeSystem::boolType, SymbolTable::getLabel()));
    new CmpInstruction(CmpInstruction::NEQ, temp, dst, new Operand(new ConstantSymbolEntry(TypeSystem::intType, 0)), bb);
    true_list.push_back(new CondBrInstruction(truebb, tempbb, temp, bb));
    false_list.push_back(new UncondBrInstruction(falsebb, tempbb));
}